#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include "app_bt.h"
#include "app_serial.h"
#include "app_device.h"
#include "../thirdparty/log.h"

static char post_read_buffer[100];
static int buff_data_len = 0;
static char read_header[2] = {0xf1, 0xdd};

/**
 * @brief 从数组的第0向开始删除指定个数的数据
 *
 * @param cnt 指定的个数
 */
static void app_bt_rm_data_from_buff(int cnt)
{
    /*1.删除帧头之前的数据*/
    memmove(post_read_buffer, post_read_buffer + cnt, buff_data_len - cnt);
    /*2.更新缓冲区的数据长度*/
    buff_data_len -= cnt;
}
/**
 * @brief 读后预处理函数
 *
 * @param data 待处理的数据
 * @param datalen 数据长度
 * @return int 处理后的数据长度
 */
static int app_bt_post_read(char *data, int datalen)
{
    /*1.将新到的数据写入缓冲区*/
    memcpy(post_read_buffer + buff_data_len, data, datalen);
    buff_data_len += datalen;
    /*2.检查缓冲区是否存在帧头*/
    for (int i = 0; i < buff_data_len; i++)
    {
        /*3.若存在帧头*/
        if (post_read_buffer[i] == read_header[0] && post_read_buffer[i + 1] == read_header[1])
        {
            /*4.删除缓冲区内帧头之前的数据*/
            app_bt_rm_data_from_buff(i);
            /*5.判断数据长度是否满足最小的帧长度*/
            if (buff_data_len < 8)
            {
                return 0;
            }
            /*6.查看缓冲区内剩余数据是否满足长度帧头的值*/
            int expect_len = post_read_buffer[2];
            /*7.若长度满足就将数据取出进行拼接/不满足返回0*/
            if (buff_data_len >= expect_len + 3)
            {
                /*7.1取出id*/
                char id_buff[2];
                memcpy(id_buff, post_read_buffer + 3, 2);
                /*7.2取出数据*/
                int msg_len = expect_len - 4;
                char msg_buff[msg_len];
                memcpy(msg_buff, post_read_buffer + 3 + 4, msg_len);
                /*7.3按规定的数据结构重新拼接*/
                data[0] = 0x01;
                data[1] = 2;
                data[2] = msg_len;

                memcpy(data + 3, id_buff, 2);
                memcpy(data + 3 + 2, msg_buff, msg_len);
                /*7.4更新缓冲区中的数据*/
                app_bt_rm_data_from_buff(expect_len + 3);
                /*7.5返回处理后的数据长度*/
                datalen = 3 + 2 + msg_len;
                return datalen;
            }
        }
    }

    return 0;
}

/**
 * @brief 写前预处理函数
 *
 * @param data 处理的数据
 * @param datalen 数据长度
 * @return int 处理后的数据长度
 *    处理前： conn_type id长度   数据长度   id  数据
 *    处理后： write_header  id   数据   write_tailer
 */

static char write_header[8] = {0x41, 0x54, 0x2b, 0x4d, 0x45, 0x53, 0x48, 0x00};
static char write_tailer[2] = {0x0d, 0x0a};
static int app_bt_pre_write(char *data, int datalen)
{
    char tmp_data[100];
    /*1.拼接蓝牙格式数据的头部*/
    memcpy(tmp_data, write_header, 8);
    /*2.拼接id和真正有效的数据*/
    memcpy(tmp_data + 8, data + 3, datalen - 3);
    /*3.拼接蓝牙格式数据的尾部*/
    memcpy(tmp_data + 8 + datalen - 3, write_tailer, 2);
    datalen = datalen - 3 + 8 + 2;
    /*4.将拼接好的数据移动到原本的缓冲区*/
    memcpy(data, tmp_data, datalen);
    /*5.返回处理后的数据长度*/
    return datalen;
}

/**
 * @brief 向蓝牙发送命令的函数
 *
 * @param dev  设备指针
 * @param cmd 命令字符串
 * @param cmd_len 字符串长度
 * @return int 成功返回0 失败返回-1
 */
static int App_bt_sendcmd(app_dev_t *dev, char *cmd, int cmd_len)
{
    int res = write(dev->dev_fd, cmd, cmd_len);
    if (res < cmd_len)
    {
        perror("send cmd fail\n");
        return -1;
    }
    return 0;
}

/*等待蓝牙回应*/
static int App_bt_waitack(app_dev_t *dev)
{
    DELAY; // 等待50ms
    char res[4];
    read(dev->dev_fd, res, 4);
    if (memcmp(res, "OK\r\n", 4) == 0)
    {
        return 0;
    }
    return -1;
}

/*蓝牙连通性测试*/
static int App_bt_conn_test(app_dev_t *dev)
{
    App_bt_sendcmd(dev, "AT\r\n", 4);
    return App_bt_waitack(dev);
}

/**
 * @brief 设置蓝牙默认参数
 *
 * @param dev 设备指针
 * @return int 成功返回0 失败返回-1
 */
static int App_bt_set_deafult_config(app_dev_t *dev)
{
    /*1.进行蓝牙连通性测试[确保主机与蓝牙模块的串口波特率一致]*/
    /*1.1将串口调至非阻塞模式以便蓝牙的连通性测试*/
    App_serial_set_isblock(dev, NO_BLOCK_MODE);
    tcflush(dev->dev_fd,TCIOFLUSH);
    int res = App_bt_conn_test(dev);
    if (res == -1)
    {
        /*2.若测试失败将主机串口波特率调至9600*/
        App_serial_set_baudrate(dev,BR_9600);
        tcflush(dev->dev_fd,TCIOFLUSH);
        /*2.1在9600的波特率下再次测试*/
        res = App_bt_conn_test(dev);
        /*2.2若测试仍然失败打印调试信息返回-1*/
        if (res == -1)
        {
            log_error("connect fail,please check bt\n");
            return -1;
        }
        /*2.3若测试成功则发送命令将蓝牙的波特率调整为115200*/
        App_bt_sendcmd(dev,"AT+BAUD8\r\n",10);
        DELAY;
        /*2.4发送命令重启蓝牙使修改的波特率生效*/
        App_bt_sendcmd(dev,"AT+RESET\r\n",10);
        sleep(1);
        /*2.5将主机串口的波特率调回115200*/
        App_serial_set_baudrate(dev,BR_115200);
        tcflush(dev->dev_fd,TCIOFLUSH);
        /*2.6再次进行连通性测试*/
        res = App_bt_conn_test(dev);
        /*2.7若测试仍旧失败打印调试信息返回-1*/
        if (res == -1)
        {
            log_error("connect fail,please check bt\n");
            return -1;
        }
        
    }
    log_info("host is same with bt of baudrate\n");
    /*3若测试成功发送命令配置网络名 网络id  网络短地址*/
    App_bt_sendcmd(dev,"AT+NAMECherry\r\n",15);
    DELAY;
    App_bt_sendcmd(dev,"AT+NETID1234\r\n",14);
    DELAY;
    App_bt_sendcmd(dev,"AT+MADDR0066\r\n",14);
    DELAY;
    /*4.将主机串口重新调回阻塞模式*/
    App_serial_set_isblock(dev,BLOCK_MODE);
    tcflush(dev->dev_fd,TCIOFLUSH);
    return 0;
}
/**
 * @brief 蓝牙模块初始化
 *
 * @param dev 设备指针
 *
 * @return int 成功返回0 失败返回-1
 */
int App_bt_Init(app_dev_t *dev)
{
    /*1.配置读后预处理*/
    dev->post_read = app_bt_post_read;
    /*2.配置写前预处理*/
    dev->pre_write = app_bt_pre_write;
    /*3.配置蓝牙相关参数*/
    return App_bt_set_deafult_config(dev);
}